/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package SRMI.Tests;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import org.apache.log4j.Logger;

/**
 *
 * @author meemo
 */
public class SRMIClassLoader extends ClassLoader {

    private static Logger l = null;
    
    public SRMIClassLoader(ClassLoader parent)
    {
        super(parent);
        instance = this;
    }

    private static SRMIClassLoader instance = null;
    
    public static SRMIClassLoader getInstance()
    {
        return instance;
    }
    
    private String path = null;
    
    public void SetPath(String path)
    {        
        if(l == null)
            l = Logger.getLogger(SRMIClassLoader.class);
        this.path = path;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        try
        {
            if(l != null) l.trace("SRMIClassLoader: trying to load " + name + " ... ");
            
            Class<?> cls = null;
            try
            {
                l.trace("Trying parent.loadClass");
                cls = getParent().loadClass(name);
            }
            catch(ClassNotFoundException ex)
            {
                l.trace("Trying parent.findClass");
                cls = findClass(name);                
            }
            assert cls != null;
            if(l != null) l.trace("success");
            return cls;
        }
        catch(ClassNotFoundException ex)
        {
            l.trace("Trying the SRMI way");

            if (path == null) 
            {
                throw new ClassNotFoundException("SRMIClassLoader path not set", ex);
            }
            
            String sep = System.getProperty("file.separator");
            String file = path + sep + name.replace(".", sep) + ".class";
            InputStream stream = null;
                
            try 
            {
                if(l != null) l.trace("trying " + file + " ... ");

                stream = new File(file).toURL().openStream();
                
                byte[] bytes = new byte[stream.available()];
                stream.read(bytes);
                
                Class<?> cls = null;
                
                try
                {
                    cls = defineClass(name, bytes, 0, bytes.length);
                }
                catch(LinkageError le)
                {
                    // duplicate definition ...
                    return super.loadClass(name);
                }
                
                if(l != null) l.trace("success");
                
                return cls;
            } 
            catch (Exception ex1) 
            {
                if(l != null) l.trace("failed");
                throw new ClassNotFoundException("Can't open stream " + file, ex1);
            }
            finally 
            {
                try 
                {
                    if(stream != null)
                        stream.close();
                }
                catch (IOException ex1) 
                {
                   throw new ClassNotFoundException("Can't close stream " + file, ex1);
                }
            }
        }
    }
}
